/**
 * 给定一个无向带权图，要求找到一个简单环，使得其最小边权最小。
 * 首先跑一个边双连通分量，再找出所有构成边双的最小边。
 * 然后从这个边开始做一个双向广搜，确定任意一个环即可。
 * 简单的深搜T了
 * 标程使用的是并查集找最小边
 */
#include <bits/stdc++.h>
using namespace std;

//type of edge's weight
typedef int weight_t;

#ifndef ONLINE_JUDGE
int const SIZE_OF_VERTICES = 20;
int const SIZE_OF_EDGES = 40;
#else
int const SIZE_OF_VERTICES = 300100;
int const SIZE_OF_EDGES = 1000110;
#endif

struct edge_t{
	int from,to;
	weight_t weight;
	int next;//Index of the array is used as pointers, ZERO means NULL
}Edge[SIZE_OF_EDGES];
int ECnt;
int Vertex[SIZE_OF_VERTICES];

//Don't forget calling it
//n is the amount of vertices
inline void initGraph(int n){
	ECnt = 2;
	fill(Vertex,Vertex+n+1,0);
}

//双向边
inline void mkEdge(int a,int b,weight_t w=weight_t()){
	Edge[ECnt].from = a;
	Edge[ECnt].to = b;
	Edge[ECnt].weight = w;
	Edge[ECnt].next = Vertex[a];
	Vertex[a] = ECnt ++;

	Edge[ECnt].from = b;
	Edge[ECnt].to = a;
	Edge[ECnt].weight = w;
	Edge[ECnt].next = Vertex[b];
	Vertex[b] = ECnt ++;
}

int Stack[SIZE_OF_VERTICES],StackTop;//辅助栈
int TimeStamp;
int Dfn[SIZE_OF_VERTICES], Low[SIZE_OF_VERTICES];
//bool IsBridge[SIZE_OF_EDGES];//边i是否为桥
bool IsVisited[SIZE_OF_EDGES];//边的标记数组，有重边时需用此数组进行判断
int Belong2BiCC[SIZE_OF_VERTICES];//点i属于第Bi个双连通分量，从1开始
int Represent[SIZE_OF_VERTICES];//Ri表示第i个边双的代表，也就是编号最小的那个点
int BiCCCnt;//双连通分量的数量

int Lightest;

void dfs(int u,int pre){
    Dfn[u] = Low[u] = ++TimeStamp;

    //入栈
    Stack[StackTop++] = u;

    //对u的每一条边
    int v,son=0;
    for(int next=Vertex[u];next;next=Edge[next].next)if( !IsVisited[next] ){
        IsVisited[next] = IsVisited[next^1] = true;

        if ( 0 == Dfn[v=Edge[next].to] ){
            ++son;
            dfs(v,u);
            if ( Low[v] < Low[u] ) Low[u] = Low[v];

            /*//桥
            if ( Dfn[u] < Low[v] ){
                IsBridge[next] = IsBridge[next^1] = true;
            }
            //*/

        }else if ( Dfn[v] < Low[u] ){
            Low[u] = Dfn[v];
        }
    }

    if ( Low[u] == Dfn[u] ){//u和其上的点在同一个分量中
        Represent[Belong2BiCC[u] = ++BiCCCnt] = u;
        do{
            Belong2BiCC[v=Stack[--StackTop]] = BiCCCnt;
            if ( v < Represent[BiCCCnt] ) Represent[BiCCCnt] = v;
        }while( v != u );
    }
}

void Tarjan(int vn){
    fill(Dfn,Dfn+vn+1,0);
    fill(Belong2BiCC,Belong2BiCC+vn+1,0);
    fill(IsVisited,IsVisited+ECnt,false);
    //fill(IsBridge,IsBridge+ECnt,false);
    BiCCCnt = StackTop = 0;

    TimeStamp = 0;

    for(int i=1;i<=vn;++i)if ( 0 == Dfn[i] )dfs(i,i);
}

int N, M;
vector<int> E;
vector<int> Flag;
vector<int> Pre;

void proc(int e, int start, int end1, int target, int end2){
	vector<int> vec;
	vec.reserve(N);
    for(int i=end1;i!=start;i=Pre[i]){
		vec.emplace_back(i);
	}
	vec.emplace_back(start);
	vector<int> vo;
	for(int i=end2;i!=target;i=Pre[i]){
		vo.emplace_back(i);
	}
	vo.emplace_back(target);
	cout << Edge[e].weight << " " << vec.size() + vo.size() << "\n";
	for(int i=vec.size()-1;i>=0;--i)cout<<vec[i]<<" ";
	for(auto i : vo) cout << i << " ";
	cout << "\n";
}

void proc(int e){
    int start = Edge[e].from;
	int target = Edge[e].to;
    
	Flag.assign(N + 1, 0);
	Flag[start] = 1; Flag[target] = 2;

	Pre.assign(N + 1, 0);

	queue<int> q1, q2;
	q1.push(start); q2.push(target);

    int b = Belong2BiCC[start];
    int sz;
	while(1){
		bool flag = false;
		while(sz = q1.size()){
			flag = true;
			while(sz--){
                auto h = q1.front(); q1.pop();
				for(int p=Vertex[h];p;p=Edge[p].next){
					int to = Edge[p].to;
					if(Belong2BiCC[to] != b) continue;

                    if(2 == Flag[to]) {
                        if(h == start and to == target) continue;
                        return proc(e, start, h, target, to);
					}else if(0 == Flag[to]){
						Flag[to] = 1;
						Pre[to] = h;
						q1.push(to);
					}
				}
			}
		}
		while(sz=q2.size()){
			flag = true;
			auto h = q2.front(); q2.pop();
			for(int p=Vertex[h];p;p=Edge[p].next){
				int to = Edge[p].to;
				if(Belong2BiCC[to] != b) continue;

				if(1 == Flag[to]) {
					if(h == target and to == start) continue;
                    return proc(e, start, to, target, h);
				}else if(0 == Flag[to]){
					Flag[to] = 2;
					Pre[to] = h;
					q1.push(to);
				}
			}
		}
	}

	return;
}

void proc(){
	Tarjan(N);
	int ligth = 0;
	for(int i=2;i<ECnt;i+=2){
		int a = Edge[i].from;
		int b = Edge[i].to;
		int w = Edge[i].weight;
		if(Belong2BiCC[a] == Belong2BiCC[b]){
			if(0 == ligth or Edge[ligth].weight > w){
				ligth = i;
			}
		}
	}

    proc(ligth);
    return;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("z.txt", "r", stdin);
#endif
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(0);
    int nofkase = 1;
    cin >> nofkase;
    while(nofkase--){
        cin >> N >> M;
		initGraph(N);
		for(int a,b,w,i=1;i<=M;++i){
			cin >> a >> b >> w;
			mkEdge(a, b, w);
		}
		proc();
    }
    return 0;
}